package com.dx.controller;

import com.dx.config.WeChatProperties;
import com.dx.domin.WeChatParams;
import com.dx.utils.HttpUtil;
import com.dx.utils.PayForUtil;
import com.dx.utils.XMLUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author
 */
@Slf4j
@RestController
@RequestMapping("/wx")
public class WeixinPayController {
    private static final int BLACK = 0xff000000;
    private static final int WHITE = 0xFFFFFFFF;

    /**
     * pc端微信支付之后的回调方法
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/notify")
    public void wechatNotifyUrlPc(HttpServletRequest request, HttpServletResponse response) throws Exception {
    }


    //微信支付接口
    @GetMapping("/pay")
    public void wxPay(HttpServletResponse response) throws Exception {
        WeChatParams ps = new WeChatParams();
        ps.setBody("商品描述");
        //商品价格,注意是以分为单位,后面不能有小数点
        // 测试用一分
        ps.setTotal_fee("1");
        //自己项目的订单ID
        ps.setOut_trade_no("123");
        //附加参数,随便设置
        ps.setAttach("111");
        //调用微信统一下单API返回二维码的code
        /**
         * 账号信息
         */
        String appid = WeChatProperties.appId;//微信服务号的appid
        String mch_id = WeChatProperties.mchId; //微信支付商户号
        String key = WeChatProperties.apiKey; // 微信支付的API密钥
        String notify_url = WeChatProperties.weChat_notify_url_pc;//回调地址【注意，这里必须要使用外网的地址】
        String ufdoder_url = WeChatProperties.ufdoderUrl;//微信下单API地址
        String tradeType = WeChatProperties.tradeType;//微信下单API地址

        /**
         * 时间字符串
         */
        String currTime = PayForUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayForUtil.buildRandom(4) + "";
        String nonce_str = strTime + strRandom;

        /**
         * 参数封装
         */
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);//随机字符串
        packageParams.put("body", ps.getBody());//支付的商品名称
        packageParams.put("out_trade_no", ps.getOut_trade_no());//商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】
        packageParams.put("total_fee", ps.getTotal_fee());//支付金额
        packageParams.put("spbill_create_ip", PayForUtil.localIp());//客户端主机
        packageParams.put("notify_url", notify_url);//回调地址就是上面的路径
        packageParams.put("trade_type", tradeType);//支付方式
        packageParams.put("limit_pay", "no_credit");//限制用户不能使用信用卡
        packageParams.put("device_info", "WEB");//设备号
        packageParams.put("attach", ps.getAttach());//额外的参数【业务类型+会员ID+支付类型】


        String sign = PayForUtil.createSign("UTF-8", packageParams, key);  //获取签名
        packageParams.put("sign", sign);

        String requestXML = PayForUtil.getRequestXml(packageParams);//将请求参数转换成String类型
        log.info("微信支付请求参数的报文" + requestXML);
        String resXml = HttpUtil.postData(ufdoder_url, requestXML);  //解析请求之后的xml参数并且转换成String类型
        Map map = XMLUtil.doXMLParse(resXml);
        log.info("微信支付响应参数的报文" + resXml);
        String result;
        if (map.get("return_code").equals("SUCCESS") && map.get("result_code").equals("SUCCESS")) {
            result = (String) map.get("code_url");
        } else {
            throw new RuntimeException(map.get("err_code_des").toString());
        }

        String urlCode = getCodeUrl(ps);
        //生成二维码输出给前台
        //encodeQrcode(urlCode, response);

        /*
        //测试把二维码输出到本地,正式环境通过流给前端
        HashMap<EncodeHintType, String> map = new HashMap<>();
        map.put(EncodeHintType.CHARACTER_SET, "utf-8");
        BitMatrix bitMatrix;
        bitMatrix = new MultiFormatWriter().encode(urlCode, BarcodeFormat.QR_CODE, 250, 250,map );
        StringBuilder path =new StringBuilder();
        path.append("C:\\Users\\Administrator\\Desktop\\demo\\");
        path.append("wx22.jpg");
        Path file = new File(path.toString()).toPath();
        MatrixToImageWriter.writeToPath(bitMatrix, "jpg", file);*/
    }

    public String getCodeUrl(WeChatParams ps) throws Exception {
        /**
         * 账号信息
         */
        String appid = WeChatProperties.appId;//微信服务号的appid
        String mch_id = WeChatProperties.mchId; //微信支付商户号
        String key = WeChatProperties.apiKey; // 微信支付的API密钥
        String notify_url = WeChatProperties.weChat_notify_url_pc;//回调地址【注意，这里必须要使用外网的地址】
        String ufdoder_url = WeChatProperties.ufdoderUrl;//微信下单API地址
        String tradeType = WeChatProperties.tradeType;//微信下单API地址

        /**
         * 时间字符串
         */
        String currTime = PayForUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayForUtil.buildRandom(4) + "";
        String nonce_str = strTime + strRandom;

        /**
         * 参数封装
         */
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);//随机字符串
        packageParams.put("body", ps.getBody());//支付的商品名称
        packageParams.put("out_trade_no", ps.getOut_trade_no());//商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】
        packageParams.put("total_fee", ps.getTotal_fee());//支付金额
        packageParams.put("spbill_create_ip", PayForUtil.localIp());//客户端主机
        packageParams.put("notify_url", notify_url);//回调地址
        packageParams.put("trade_type", tradeType);//支付方式
        packageParams.put("limit_pay", "no_credit");//限制用户不能使用信用卡
        packageParams.put("device_info", "WEB");//设备号
        packageParams.put("attach", ps.getAttach());//额外的参数【业务类型+会员ID+支付类型】


        String sign = PayForUtil.createSign("UTF-8", packageParams, key);  //获取签名
        packageParams.put("sign", sign);

        String requestXML = PayForUtil.getRequestXml(packageParams);//将请求参数转换成String类型
        log.info("微信支付请求参数的报文" + requestXML);
        String resXml = HttpUtil.postData(ufdoder_url, requestXML);  //解析请求之后的xml参数并且转换成String类型
        Map map = XMLUtil.doXMLParse(resXml);
        log.info("微信支付响应参数的报文" + resXml);
        String result;
        if (map.get("return_code").equals("SUCCESS") && map.get("result_code").equals("SUCCESS")) {
            result = (String) map.get("code_url");
        } else {
            throw new RuntimeException(map.get("err_code_des").toString());
        }
        return result;
    }

    /**
     * 将路径生成二维码图片
     *
     * @param content
     * @param response
     * @author pzh
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void encodeQrcode(String content, HttpServletResponse response) {

        if (StringUtils.isBlank(content)) {
            return;
        }
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        Hashtable hints = new Hashtable();
        //设置容错级别最高
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        //设置字符编码为utf-8
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        //二维码空白区域,最小为0也有白边,只是很小,最小是6像素左右
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 250, 250, hints);
            BufferedImage image = toBufferedImage(bitMatrix);
            //输出二维码图片流
            try {
                response.setHeader("Content-Type", "image/jpeg");
                ImageIO.write(image, "png", response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (WriterException e1) {
            e1.printStackTrace();
        }

    }

    /**
     * 类型转换
     *
     * @param matrix
     * @return
     * @author pzh
     */
    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) == true ? BLACK : WHITE);
            }
        }
        return image;
    }


}